#include<iostream>
using namespace std;

//请设计一个类，只能在堆上创建对象
class HeapOnly
{
public:
	static HeapOnly* CreateObj()//提供一个成员函数，完成堆对象的创建，且该成员函数还必须是静态的
	{                           //因为非静态成员函数必须用对象来调用，而对象必须调用CreateObj来创建
		return new HeapOnly;    //静态成员函数才支持：HeapOnly* ptr1 = HeapOnly::CreateObj();
	}

	HeapOnly(const HeapOnly& ho) = delete;//拷贝构造直接delete掉，因为拷贝构造出的对象是在栈上的
private:
	HeapOnly()//构造函数能设置为私有但不能直接delete，因为之后CreateObj还要用它创建对象
		:_a(0)
	{}
private:
	int _a;
};

class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		return StackOnly();
	}
	//不用封拷贝构造，因为拷贝构造出来的就是在栈上的

	// 禁掉StackOnly的operator new可以把下面用new 调用拷贝构造申请对象给禁掉
	// StackOnly obj = StackOnly::CreateObj();
	// StackOnly* ptr3 = new StackOnly(obj);//此处的new调的是拷贝构造
	void* operator new(size_t size) = delete;
	void operator delete(void* p) = delete;
private:
	StackOnly()
		:_a(0)
	{}

private:
	int _a;
};

//请设计一个类，不能被拷贝
//拷贝只会放生在两个场景中：拷贝构造函数以及赋值运算符重载，因此想要让一个类禁止拷贝，
//只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

//C++98 
//将拷贝构造函数与赋值运算符重载只声明不定义，并且将其访问权限设置为私有即可。
class CopyBan_c98
{
	// ...

private:
	CopyBan_c98(const CopyBan_c98&);
	CopyBan_c98& operator=(const CopyBan_c98&);
	//...
};

//C++11
//C++11扩展delete的用法，delete除了释放new申请的资源外，如果在默认成员函数后跟上= delete，表示让编译器删除掉该默认成员函数。
class CopyBan_c11
{
	// ...
	CopyBan_c11(const CopyBan_c11&) = delete;
	CopyBan_c11& operator=(const CopyBan_c11&) = delete;
	//...
};

//int main()
//{
//	//HeapOnly ho1;
//	//HeapOnly* pho = new HeapOnly;
//	HeapOnly* ptr1 = HeapOnly::CreateObj();
//	//HeapOnly copy(*ptr);
//
//	//StackOnly* ptr2 = new StackOnly;
//	StackOnly obj = StackOnly::CreateObj();
//	//StackOnly* ptr3 = new StackOnly(obj);
//
//	return 0;
//}


//请设计一个类，不能被继承
//附：
//C++有规定：子类要初始化父类的部分必须调用父类的构造函数，要清理父类的部分必须调用父类的析构函数。
//           拷贝和赋值时，父类的部分也是要调用父类的拷贝和赋值
//父类的private成员在子类是不可见的

//C++98方式
//父类的构造函数私有化，子类中调不到父类的构造函数。则无法继承。eg:
class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

//C++11方式
//final关键字，final修饰类，表示该类不能被继承。
class A final 
{
	// ....
};




int main()
{

	return 0;
}



